package br.com.locanet.dao;

import java.util.Collections;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.Query;

import br.com.locanet.bean.IEntity;
import br.com.locanet.util.UtilReflection;

@SuppressWarnings("unchecked")
public class GenericJPADAO<ENTITY extends IEntity> implements DAO<ENTITY>{

    private String persistenceUnit = "locanet";
    private EntityManager em;
	private static EntityManagerFactory emf ;
	
	private EntityManager getEntityManager() {
		  if (emf == null) {
	           emf = Persistence.createEntityManagerFactory(getPersistenceUnit());
	       }
	       return emf.createEntityManager();
	}
	private void close() {
		if(em!=null&& em.isOpen()){
			em.close();
		}
	}
	/**
	 * @return the persistenceUnit
	 */
	public String getPersistenceUnit() {
		return persistenceUnit;
	}
	/**
	 * @param persistenceUnit the persistenceUnit to set
	 */
	public void setPersistenceUnit(String persistenceUnit) {
		this.persistenceUnit = persistenceUnit;
	}
	
	public Class<?> getEntityType(){
		return UtilReflection.getGenericClassType(getClass());
	}

	@Override
	public void delete(ENTITY entity) throws PersistenceException {
		if(entity!=null && entity.getId()!=null){
		    em=getEntityManager();
			EntityTransaction tx= em.getTransaction();
			try{
				tx.begin();
				entity = em.merge(entity);
				em.remove(entity);
				tx.commit();
				close();
			}catch(RuntimeException re){
				tx.rollback();
				throw re;
			}
	    }else{
	    	throw new PersistenceException("deleteDAOEntityNULL");
	    }
	}


	
	@Override
	public List<ENTITY> find(String queryName, Object[] args)
			throws PersistenceException {
		em=getEntityManager();
		Query query = em.createQuery(queryName);
		List<ENTITY> result=null;
		setParamiters(query,args);
		result=query.getResultList();
		close();
		return result;
	}

	private void setParamiters(Query query, Object[] args) {
		if(args!=null){
			int i=1;
			for (Object object : args) {
				query.setParameter(i, object);
				i++;
			}
		}
		
	}
	@Override
	public List<ENTITY> findAll() throws PersistenceException {
		StringBuffer query = new StringBuffer();
		query.append("select oEntidade from "+getEntityType().getName()+" oEntidade ");
		return (List<ENTITY>) find(query.toString(), new Object[0]);
	}

	@Override
	public ENTITY findById(ENTITY entity) throws PersistenceException {
	    em = getEntityManager();
		if(entity==null){
			throw new PersistenceException("findByIdDAOEntityNULL");
		}
		entity =(ENTITY) em.find(entity.getClass(), entity.getId());
		close();
		return entity;
	}

	@Override
	public List<ENTITY> findNavite(String nativeQuery) throws PersistenceException {
		em=getEntityManager();
		Query query = em.createNativeQuery(nativeQuery);
		List<ENTITY> result=null;
		result=query.getResultList();
		close();
		return result;
	}

	@Override
	public List<ENTITY> findNavite(String nativeQuery, Object[] args)
			throws PersistenceException {
		em=getEntityManager();
		Query query = em.createNativeQuery(nativeQuery);
		List<ENTITY> result=null;
		setParamiters(query,args);
		result=query.getResultList();
		close();
		return result;
	}

	@Override
	public ENTITY insert(ENTITY entity) throws PersistenceException {
		if(entity.getId()==null){
			em=getEntityManager();
			EntityTransaction tx= em.getTransaction();
			try{
				tx.begin();
				em.persist(entity);
				tx.commit();
				em.refresh(entity);
				close();
			}catch(PersistenceException e){
				tx.rollback();
				throw e;
			}
		}else{
			throw new PersistenceException("insertDAOidNotNULL");
		}
		return entity;
	}

	@Override
	public ENTITY update(ENTITY entity) throws PersistenceException {
		if(entity.getId()!=null){
			em=getEntityManager();
			EntityTransaction tx= em.getTransaction();
			try{
				tx.begin();
				entity = em.merge(entity);
				tx.commit();
				close();
			}catch(PersistenceException e){
				tx.rollback();
				throw e;
			}
		}else{
			throw new PersistenceException("updateDAOidNULL");
		}
		return entity;	
	}

	@Override
	public List<ENTITY> findByNamedQuery(String queryName, Object[] args)
			throws PersistenceException {
		em=getEntityManager();
		Query query=em.createNamedQuery(queryName);
		List<ENTITY> result=Collections.EMPTY_LIST;
		setParamiters(query, args);
		result=query.getResultList();
		close();
		return result;
	}	
	
	protected void doPrepareQueryFrom(StringBuffer query,ENTITY entity){
	}
	  
	public List<ENTITY> find(ENTITY entity) throws PersistenceException{
		StringBuffer query = new StringBuffer();
		query.append("select oEntidade from "+getEntityType().getName()+" oEntidade ");
		doPrepareQueryFrom(query, entity);
		query.append(" where 1=1 ");
		Object[] args = doPrepareQuery(query,entity);
		return (List<ENTITY>) find(query.toString(), args);
    }
    
	protected Object[] doPrepareQuery(StringBuffer query,ENTITY entity){
		return new Object[0];
    }
	
}
